/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package locusts.server.behaviours;

import java.util.Random;
import javax.vecmath.Vector2d;
import locusts.common.entities.Actor;
import locusts.common.entities.Entity;
import locusts.common.entities.EntityData;
import locusts.common.entities.EntityDataList;
import locusts.common.entities.EntityList;
import locusts.lib.MathUtil;

/**
 *
 * @author hamish
 */
public class BehaviourSystem {

    private final EntityList entities;
    private final EntityDataList data;

    public BehaviourSystem(EntityList entities, EntityDataList data) {
        this.entities = entities;
        this.data = data;
    }

    private void initialize() {
        for (EntityData d : data) {
            if (d == null || !d.isBehaviourSet())
                continue;
            Behaviour behaviour = d.getBehaviour();
            behaviour.initialize(entities);
        }
    }

    public void update(double time) {
        final double maxAcceleration = 200; // px/s/s

        final Random rand = new Random();
        initialize();

        for (Entity e : entities) {

            if (!(e instanceof Actor))
                continue;
            Actor a = (Actor) e;

            if (!a.isAlive())
                continue;

            EntityData aData = data.get(a);

            if (rand.nextDouble() > 0.1d)
                continue;

            if (!aData.isBehaviourSet())
                continue;

            Behaviour behaviour = aData.getBehaviour();

            Vector2d steering = behaviour.getSteering(a);

            if (Double.isNaN(steering.x) || Double.isNaN(steering.y) ||
                    Double.isInfinite(steering.x) || Double.isInfinite(
                    steering.x))
                throw new RuntimeException("Steering is NaN: {}" +
                        steering);

            // If the vector is small then don't bother doing anything else
            // if it's zero it may cause divide by zero errors anyway
            if (MathUtil.epsilonEqual(steering.lengthSquared(), 0, 1e-10d))
                continue;
            // max acceleration in pixels per second per second

            Vector2d tmp = (Vector2d) steering.clone();
            steering.normalize();

            if (Double.isNaN(steering.x) || Double.isNaN(steering.y) ||
                    Double.isInfinite(steering.x) || Double.isInfinite(
                    steering.x)) {
                System.out.println("before: " + tmp);
                System.out.println("after:" + steering);
                throw new RuntimeException("Steering is NaN: {}" +
                        steering);
            }

            steering.scale(maxAcceleration);

            if (Double.isNaN(steering.x) || Double.isNaN(steering.y) ||
                    Double.isInfinite(steering.x) || Double.isInfinite(
                    steering.x))
                throw new RuntimeException("Steering is NaN: {}" +
                        steering);

            a.setAcceleration(steering.x, steering.y);
            a.setModified();


        }
        clean();

    }

    private void clean() {
        for (EntityData d : data) {
            if (d == null || !d.isBehaviourSet())
                continue;
            Behaviour behaviour = d.getBehaviour();
            behaviour.clean();
        }
    }
}
